/* 
 * File:   Enviroment.cpp
 * Author: flai0014
 * 
 * Created on March 30, 2012, 11:48 AM
 */

#include "Enviroment.h"

Enviroment::Enviroment() { 
    count_Wait = false;
    print_Wait = true;
    m_numOfParticles = 0;
    Particle* tmp;
    m_enviroment.resize(VERTICAL_SIZE);
    for(int i = 0; i < VERTICAL_SIZE; i++){
        m_enviroment[i].resize(HORIZONTAL_SIZE);
    }
    for(int k = 0; k < VERTICAL_SIZE; k++){
        for(int j = 0; j < HORIZONTAL_SIZE; j++){
            m_enviroment[k][j] = new EnvCell();
            if(m_numOfParticles < NUM_OF_PARTICLES){
                for(int h = 0; h < (NUM_OF_PARTICLES/HORIZONTAL_SIZE+1) && 
                                m_numOfParticles < NUM_OF_PARTICLES; h++){
                    tmp = new Particle();
                    m_enviroment[k][j]->addParticle(tmp);
                    m_numOfParticles++;
                }//end for
            }//end if
        }//end for
    }//end for

}
    
void Enviroment::checkParticles(){
    pthread_mutex_lock(&m_mutex);
    count_Wait = true;
    int particleCount = 0;
    while(agentCount < MAX_AGENTS){
        cerr << "Signaling agents to check in:\n";
        pthread_cond_signal(&wait_condition_var);
        cerr << "Waiting for agent check-in: " << agentCount << endl;
        pthread_cond_wait(&count_condition_var, &m_mutex);
    }
    for(int k = 0; k < VERTICAL_SIZE; k++){
        for(int j = 0; j < HORIZONTAL_SIZE; j++){
            particleCount += m_enviroment[k][j]->countParticles();            
        }
    }
    if(particleCount != PARTICLE_CHECK){
        cerr << "Particle count is bad: " << particleCount << endl;
        exit(1);
    }
    else{
        cout << "Particle count is good: Restarting threads: \n";
        count_Wait = false;
        agentCount = 0;
        pthread_cond_broadcast(&wait_condition_var);
        pthread_mutex_unlock(&m_mutex);
    }
}
    
void Enviroment::printEnviroment(){
    pthread_mutex_lock(&m_mutex);
    cerr << "Holding mutex lock in print:\n";
    print_Wait = true;
    while(agentCount < MAX_AGENTS){
        cerr << "Signaling agents to check in:\n";
        pthread_cond_signal(&wait_condition_var);
        cerr << "Waiting for agent check-in: " << agentCount << endl;
        pthread_cond_wait(&count_condition_var, &m_mutex);
    }
    for(int k = 0; k < VERTICAL_SIZE; k++){
        for(int j = 0; j < HORIZONTAL_SIZE; j++){
            if(m_enviroment[k][j]->numberOfParticles() < 10)
                cerr << " " << m_enviroment[k][j]->numberOfParticles();
            else
                cerr << m_enviroment[k][j]->numberOfParticles();
            if(m_enviroment[k][j]->hasAgent())
                cerr << "* ";
            else
                cerr << "  ";
            
        }
        cerr << "\n";
    }
    print_Wait = false;
    agentCount = 0;
    pthread_cond_broadcast(&wait_condition_var);
    pthread_mutex_unlock(&m_mutex);
}

void Enviroment::startAgents(){
    pthread_mutex_lock(&m_mutex);
    print_Wait = false;
    pthread_cond_broadcast(&wait_condition_var);
    pthread_mutex_unlock(&m_mutex);
}

void Enviroment::waitAgents(){
    pthread_mutex_lock(&m_mutex);
    print_Wait = true;
    while(agentCount < MAX_AGENTS){
        pthread_cond_wait(&count_condition_var, &m_mutex);
    }
    pthread_mutex_unlock(&m_mutex);
}


Enviroment::~Enviroment() {
    pthread_mutex_lock(&m_mutex);
    while(agentCount < MAX_AGENTS){
        pthread_cond_wait(&count_condition_var, &m_mutex);
    }
    pthread_mutex_unlock(&m_mutex);
    EnvCell* tmp;
    for(int k = 0; k < VERTICAL_SIZE; k++){
        for(int j = 0; j < HORIZONTAL_SIZE; j++){
            tmp = m_enviroment[k][j];
            delete tmp;
        }
    }
}

pthread_mutex_t Enviroment::m_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t Enviroment::count_condition_var =  PTHREAD_COND_INITIALIZER;
pthread_cond_t Enviroment::wait_condition_var =  PTHREAD_COND_INITIALIZER;
int Enviroment::agentCount = 0;
bool Enviroment::count_Wait;
bool Enviroment::print_Wait;
vector<vector<EnvCell*> > Enviroment::m_enviroment;
